/*
 * Copyright(c)2021, 长春吉大正元信息安全技术有限公司 All Rights Reserved.
 *   项目名称: zero-trust
 *   文件名称: CopyUtils.java
 *   Date: 11/26/21 9:58 AM
 *   Version: 1.0
 *   LastModified: 11/26/21 9:33 AM
 *   Author: xinzhi_yu@jit.com.cn
 */

package com.core.website.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.cglib.beans.BeanCopier;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 用于处理两个示例属性赋值
 *
 * @author xinzhi_yu@jit.com.cn
 * @version 1.0
 * <p>date: 11/26/21 1:09 PM
 */
@Slf4j
public class CopyUtils {

    /**
     * 用于缓存创建的转换模板
     */
    private static final ConcurrentHashMap<String, BeanCopier> BEAN_COPIER_CACHE = new ConcurrentHashMap<>();

    /**
     * 拷贝对象属性 注意, 只有当对象的成员变量名和其类型皆匹配时才会拷贝过去
     * <p>如果有属性名不同或者属性名相同但属性的类型不同时, 该属性值不会被拷贝
     *
     * @param source:      源对象
     * @param targetClass: 目标对象的class
     * @return 拷贝源对象属性值后, 目标对象的示例
     * @author xinzhi_yu@jit.com.cn
     * @version 1.0
     * <p>date: 11/26/21 10:39 AM
     */
    public static <T> T copy(Object source, Class<T> targetClass) {
        if (source == null) {
            return createInstance(targetClass);
        }
        String key = genKey(source.getClass(), targetClass);
        BeanCopier beanCopier;
        if (BEAN_COPIER_CACHE.containsKey(key)) {
            beanCopier = BEAN_COPIER_CACHE.get(key);
        } else {
            beanCopier = BeanCopier.create(source.getClass(), targetClass, false);
            BEAN_COPIER_CACHE.put(key, beanCopier);
        }
        T targetObj = null;
        targetObj = createInstance(targetClass);
        beanCopier.copy(source, targetObj, null);
        return targetObj;
    }

    private static <T> T createInstance(Class<T> targetClass) {
        T targetObj = null;
        try {
            targetObj = targetClass.newInstance();
        } catch (Exception e) {
            log.error("CopyUtil.copy() 创建目标类实例失败, error: ", e);
          //  throw new ZtException(ResponseCodeEnum.FAILED, e);
        }
        return targetObj;
    }

    /**
     * 拷贝对象属性 注意, 只有当对象的成员变量名和其类型皆匹配时才会拷贝过去
     * <p>如果有属性名不同或者属性名相同但属性的类型不同时, 该属性值不会被拷贝
     *
     * @param source: 源对象
     * @param target: 目标对象
     * @author xinzhi_yu@jit.com.cn
     * @version 1.0
     * <p>date: 11/26/21 10:39 AMTt
     */
    public static <T> T copy(Object source, T target) {
        if (source == null) {
            return target;
        }
        String key = genKey(source.getClass(), target.getClass());
        BeanCopier beanCopier;
        if (BEAN_COPIER_CACHE.containsKey(key)) {
            beanCopier = BEAN_COPIER_CACHE.get(key);
        } else {
            beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
            BEAN_COPIER_CACHE.put(key, beanCopier);
        }
        beanCopier.copy(source, target, null);
        return target;
    }

    /**
     * 列表复制
     *
     * @param sourceList : 源数据列表
     * @param targetClass : 目标数据类型
     * @return  目标数据列表 源数据为空则返回空列表
     * @author xinzhi_yu@jit.com.cn
     * @version 1.0
     * <p>date: 12/16/21 8:05 PM
     */
    public static <T> List<T> copy(List sourceList, Class<T> targetClass) {
        if (CollectionUtils.isEmpty(sourceList)) {
            return Collections.emptyList();
        }
        List<T> targetList = new ArrayList<>(sourceList.size());
        for (Object source : sourceList) {
            targetList.add(copy(source, targetClass));
        }
        return targetList;
    }

    /**
     * 生成key
     *
     * @param srcClazz 源文件的class
     * @param tgtClazz 目标文件的class
     * @return string
     */
    private static String genKey(Class<?> srcClazz, Class<?> tgtClazz) {
        return srcClazz.getName() + tgtClazz.getName();
    }
}